﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Idlesoft.Utils;

namespace Idlesoft.ShellAnywhereLanguage
{
	public class Registry<TItem> : IRegistry<TItem>
	    where TItem : class, IParam
	{
		#region ctors
		public Registry(params TItem[] items) { Register(items); }
		#endregion ctors

		#region methods
		public void Register<TResult>(params TResult[] items) where TResult : class, TItem
		{
			if (!items.IsNullOrEmpty())
				items.ForEach(item => _Items.Add(item));
		}
		public void Unregister<TResult>(params TResult[] items) where TResult : class, TItem
		{
			if (!items.IsNullOrEmpty())
				items.ForEach(item => _Items.Remove(item));
		}
		public ILexeme<TItem> Find(string pattern)
		{
			var items = _Items.Where(item => item.Matches(pattern)).ToArray();
			return new Lexeme<TItem>(!items.IsNullOrEmpty() ? pattern.Length : 0, items);
		}
		public ILexeme<TResult> Find<TResult>(string pattern)
			where TResult : class, TItem
		{
			var items = _Items.Where(item => item is TResult && item.Matches(pattern)).Cast<TResult>().ToArray();
			return new Lexeme<TResult>(!items.IsNullOrEmpty() ? pattern.Length : 0, items);
		}
		public ILexeme<TItem> Find<TConstraint>(TConstraint constraint, string pattern)
			where TConstraint : class, TItem
		{
			var associatedWiths = _Items.Where(item => constraint.IsAssociatedWith(item) && item.Matches(pattern)).ToArray();
			var constrainedBys = _Items.Where(item => item.IsConstrainedBy(constraint) && item.Matches(pattern)).ToArray();
			var items = associatedWiths.Plus(constrainedBys).Distinct().ToArray();

			return new Lexeme<TItem>(!items.IsNullOrEmpty() ? pattern.Length : 0, items);
		}

		public ILexeme<TResult> Find<TResult, TConstraint>(TConstraint constraint, string pattern)
			where TResult : class, TItem
			where TConstraint : class, TItem
		{
			var items = _Items.Where(item => item is TResult && item.IsConstrainedBy(constraint) && item.Matches(pattern)).Cast<TResult>().ToArray();
			return new Lexeme<TResult>(!items.IsNullOrEmpty() ? pattern.Length : 0, items);
		}
		#endregion methods

		#region fields
		private List<TItem> _Items = new List<TItem>();
		#endregion fields
	}
}
